﻿Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Globalization
Imports System.IO
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Runtime.Serialization
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Design
Imports System.Xml

Namespace System.Workflow.ComponentModel.Serialization
    Friend NotInheritable Class ActivitySurrogate
        Implements ISerializationSurrogate
        ' Methods
        Public Sub GetObjectData(ByVal obj As Object, ByVal info As SerializationInfo, ByVal context As StreamingContext)
            If (Activity.ContextIdToActivityMap Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_ActivitySaveLoadNotCalled"))
            End If
            Dim activity As Activity = DirectCast(obj, Activity)
            Dim isSurrounding As Boolean = False
            Dim flag2 As Boolean = Me.IsDanglingActivity(activity, isSurrounding)
            If isSurrounding Then
                If (Not activity.ContextActivity Is Nothing) Then
                    info.AddValue("cid", activity.ContextId)
                End If
                info.AddValue("id", activity.DottedPath)
                info.SetType(GetType(ActivityRef))
            ElseIf flag2 Then
                info.AddValue("id", activity.Name)
                info.AddValue("type", activity.GetType)
                info.SetType(GetType(DanglingActivityRef))
            Else
                info.AddValue("id", activity.DottedPath)
                Dim names As String() = Nothing
                Dim serializableMembers As MemberInfo() = FormatterServicesNoSerializableCheck.GetSerializableMembers(obj.GetType, names)
                Dim objectData As Object() = FormatterServices.GetObjectData(obj, serializableMembers)
                If ((objectData Is Nothing) OrElse (objectData.Length <> 2)) Then
                    info.AddValue("memberNames", names)
                    info.AddValue("memberDatas", objectData)
                Else
                    Dim dictionary As IDictionary([Of] DependencyProperty, Object) = DirectCast(objectData(0), IDictionary([Of] DependencyProperty, Object))
                    If ((Not dictionary Is Nothing) AndAlso (dictionary.Count > 0)) Then
                        Dim pair As KeyValuePair([Of] DependencyProperty, Object)
                        For Each pair In dictionary
                            If ((Not pair.Key Is Nothing) AndAlso Not pair.Key.DefaultMetadata.IsNonSerialized) Then
                                info.AddValue("memberData", objectData(0))
                                Exit For
                            End If
                        Next
                    End If
                    If (Not objectData(1) Is Nothing) Then
                        info.AddValue("disposed", objectData(1))
                    End If
                End If
                If (TypeOf obj Is Activity AndAlso (DirectCast(obj, Activity).Parent Is Nothing)) Then
                    Dim str As String = [TryCast](activity.GetValue(Activity.WorkflowXamlMarkupProperty),String)
                    If Not String.IsNullOrEmpty(str) Then
                        info.AddValue("workflowMarkup", str)
                        Dim str2 As String = [TryCast](activity.GetValue(Activity.WorkflowRulesMarkupProperty),String)
                        If Not String.IsNullOrEmpty(str2) Then
                            info.AddValue("rulesMarkup", str2)
                        End If
                    Else
                        info.AddValue("type", activity.GetType)
                    End If
                    Dim activity2 As Activity = DirectCast(activity.GetValue(Activity.WorkflowDefinitionProperty), Activity)
                    If (Not activity2 Is Nothing) Then
                        Dim list As ArrayList = DirectCast(activity2.GetValue(WorkflowChanges.WorkflowChangeActionsProperty), ArrayList)
                        If (Not list Is Nothing) Then
                            Dim guid As Guid = DirectCast(activity2.GetValue(WorkflowChanges.WorkflowChangeVersionProperty), Guid)
                            info.AddValue("workflowChangeVersion", guid)
                            [Using] writer As StringWriter = New StringWriter(CultureInfo.InvariantCulture)
                                [Using] writer2 As XmlWriter = Helpers.CreateXmlWriter(writer)
                                    New WorkflowMarkupSerializer().Serialize(writer2, list)
                                    info.AddValue("workflowChanges", writer.ToString)
                                End [Using]
                            End [Using]
                        End If
                    End If
                End If
                info.SetType(GetType(ActivitySerializedRef))
            End If
        End Sub

        Private Function IsDanglingActivity(ByVal activity As Activity, <Out> ByRef isSurrounding As Boolean) As Boolean
            isSurrounding = False
            Dim flag As Boolean = False
            Do
                If Activity.ActivityRoots.Contains(activity) Then
                    flag = False
                    Exit Do
                End If
                If (activity.Parent Is Nothing) Then
                    flag = (Not DirectCast(Activity.ActivityRoots.Item(0), Activity).RootActivity Is activity)
                    Exit Do
                End If
                If Not activity.Parent.Activities.Contains(activity) Then
                    Dim list As IList([Of] Activity) = Nothing
                    If (Not activity.Parent.ContextActivity Is Nothing) Then
                        list = DirectCast(activity.Parent.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty), IList([Of] Activity))
                    End If
                    If ((list Is Nothing) OrElse Not list.Contains(activity)) Then
                        flag = True
                        Exit Do
                    End If
                End If
                activity = activity.Parent
            Loop While (Not activity Is Nothing)
            isSurrounding = (Not flag AndAlso Not Activity.ActivityRoots.Contains(activity))
            Return flag
        End Function

        Public Function SetObjectData(ByVal obj As Object, ByVal info As SerializationInfo, ByVal context As StreamingContext, ByVal selector As ISurrogateSelector) As Object
            Return Nothing
        End Function


        ' Nested Types
        <Serializable> _
        Private NotInheritable Class ActivityRef
            Implements IObjectReference
            ' Methods
            Private Function System.Runtime.Serialization.IObjectReference.GetRealObject(ByVal context As StreamingContext) As Object Implements IObjectReference.GetRealObject
                If (Activity.ContextIdToActivityMap Is Nothing) Then
                    Throw New InvalidOperationException(SR.GetString("Error_ActivitySaveLoadNotCalled"))
                End If
                Dim activity As Activity = DirectCast(Activity.ContextIdToActivityMap.Item(Me.cid), Activity)
                Return activity.TraverseDottedPathFromRoot(Me.id)
            End Function


            ' Fields
            <OptionalField> _
            Private cid As Integer
            Private id As String = String.Empty
        End Class

        <Serializable> _
        Private NotInheritable Class ActivitySerializedRef
            Implements IObjectReference, IDeserializationCallback
            ' Methods
            Private Function Position(ByVal name As String) As Integer
                If ((Me.memberNames.Length > 0) AndAlso Me.memberNames(Me.lastPosition).Equals(name)) Then
                    Return Me.lastPosition
                End If
                If ((++Me.lastPosition < Me.memberNames.Length) AndAlso Me.memberNames(Me.lastPosition).Equals(name)) Then
                    Return Me.lastPosition
                End If
                Dim i As Integer
                For i = 0 To Me.memberNames.Length - 1
                    If Me.memberNames(i).Equals(name) Then
                        Me.lastPosition = i
                        Return Me.lastPosition
                    End If
                Next i
                Me.lastPosition = 0
                Return -1
            End Function

            Private Sub System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(ByVal sender As Object) Implements IDeserializationCallback.OnDeserialization
                If (Not Me.cachedActivity Is Nothing) Then
                    Dim flag As Boolean = False
                    Dim names As String() = Nothing
                    Dim serializableMembers As MemberInfo() = FormatterServicesNoSerializableCheck.GetSerializableMembers(Me.cachedActivity.GetType, names)
                    If (serializableMembers.Length = 2) Then
                        If ((Not Me.memberData Is Nothing) AndAlso (Not Me.disposed Is Nothing)) Then
                            FormatterServices.PopulateObjectMembers(Me.cachedActivity, serializableMembers, New Object() { Me.memberData, Me.disposed })
                            flag = True
                        ElseIf (Not Me.memberData Is Nothing) Then
                            FormatterServices.PopulateObjectMembers(Me.cachedActivity, New MemberInfo() { serializableMembers(0) }, New Object() { Me.memberData })
                            flag = True
                        ElseIf (Not Me.disposed Is Nothing) Then
                            FormatterServices.PopulateObjectMembers(Me.cachedActivity, New MemberInfo() { serializableMembers(1) }, New Object() { Me.disposed })
                            flag = True
                        End If
                    End If
                    If (Not flag AndAlso (Not Me.memberDatas Is Nothing)) Then
                        Dim data As Object() = New Object(serializableMembers.Length  - 1) {}
                        Dim i As Integer
                        For i = 0 To names.Length - 1
                            data(i) = Me.memberDatas(Me.Position(names(i)))
                        Next i
                        FormatterServices.PopulateObjectMembers(Me.cachedActivity, serializableMembers, data)
                    End If
                    Me.cachedActivity.FixUpMetaProperties(Me.cachedDefinitionActivity)
                    Me.cachedActivity = Nothing
                End If
            End Sub

            Private Function System.Runtime.Serialization.IObjectReference.GetRealObject(ByVal context As StreamingContext) As Object Implements IObjectReference.GetRealObject
                If (Activity.DefinitionActivity Is Nothing) Then
                    If ((Me.type Is Nothing) AndAlso String.IsNullOrEmpty(Me.workflowMarkup)) Then
                        Return Nothing
                    End If
                    Dim root As Activity = Nothing
                    Dim createNew As Boolean = (Not Me.workflowChanges Is Nothing)
                    root = Activity.OnResolveActivityDefinition(Me.type, Me.workflowMarkup, Me.rulesMarkup, createNew, Not createNew, Nothing)
                    If (root Is Nothing) Then
                        Throw New NullReferenceException(SR.GetString("Error_InvalidRootForWorkflowChanges"))
                    End If
                    If createNew Then
                        Dim list As ArrayList = Activity.OnResolveWorkflowChangeActions(Me.workflowChanges, root)
                        Dim action As WorkflowChangeAction
                        For Each action In list
                            action.ApplyTo(root)
                        Next
                        root.SetValue(WorkflowChanges.WorkflowChangeActionsProperty, list)
                        root.SetValue(WorkflowChanges.WorkflowChangeVersionProperty, Me.workflowChangeVersion)
                        DirectCast(root, IDependencyObjectAccessor).InitializeDefinitionForRuntime(Nothing)
                    End If
                    Activity.DefinitionActivity = root
                End If
                If (Me.cachedActivity Is Nothing) Then
                    Me.cachedDefinitionActivity = Activity.DefinitionActivity.TraverseDottedPathFromRoot(Me.id)
                    Me.cachedActivity = DirectCast(FormatterServices.GetUninitializedObject(Me.cachedDefinitionActivity.GetType), Activity)
                End If
                Return Me.cachedActivity
            End Function


            ' Fields
            <NonSerialized> _
            Private cachedActivity As Activity
            <NonSerialized> _
            Private cachedDefinitionActivity As Activity
            <OptionalField> _
            Private disposed As EventHandler
            Private id As String = String.Empty
            <NonSerialized> _
            Private lastPosition As Integer
            <OptionalField> _
            Private memberData As Object
            <OptionalField> _
            Private memberDatas As Object()
            <OptionalField> _
            Private memberNames As String()
            <OptionalField> _
            Private rulesMarkup As String
            <OptionalField> _
            Private type As Type
            <OptionalField> _
            Private workflowChanges As String
            <OptionalField> _
            Private workflowChangeVersion As Guid = Guid.Empty
            <OptionalField> _
            Private workflowMarkup As String
        End Class

        <Serializable> _
        Private Class DanglingActivityRef
            Implements IObjectReference
            ' Methods
            Private Function System.Runtime.Serialization.IObjectReference.GetRealObject(ByVal context As StreamingContext) As Object Implements IObjectReference.GetRealObject
                If (Me.activity Is Nothing) Then
                    Me.activity = DirectCast(Activator.CreateInstance(Me.type), Activity)
                    Me.activity.Name = Me.id
                End If
                Return Me.activity
            End Function


            ' Fields
            <NonSerialized> _
            Private activity As Activity
            Private id As String = String.Empty
            Private type As Type
        End Class
    End Class
End Namespace

